home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / unix / regexp.2 < prev    next >
Text File  |  1988-12-06  |  49KB  |  1,708 lines

  1. Path: xanth!nic.MR.NET!hal!cwjcc!ukma!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i086:  regexp - regular-expression routines, Part02/02
  5. Message-ID: <10485@swan.ulowell.edu>
  6. Date: 5 Dec 88 22:06:40 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1697
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: grwalter@watcgl.waterloo.edu       
  12. Posting-number: Volume 2, Issue 86
  13. Archive-name: unix/regexp.2
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    regerror.c
  23. #    regexp.3
  24. #    regexp.c
  25. #    regexp.h
  26. #    regexp.lib.uue
  27. #    regmagic.h
  28. #    regsub.c
  29. # This archive created: Mon Nov 28 19:50:58 1988
  30. cat << \SHAR_EOF > regerror.c
  31. #include <stdio.h>
  32.  
  33. void 
  34. regerror(s)
  35.     char           *s;
  36. {
  37. #ifdef ERRAVAIL
  38.     error("regexp: %s", s);
  39. #else
  40.     fprintf(stderr, "regexp(3): %s", s);
  41.     exit(1);
  42. #endif
  43.     /* NOTREACHED */
  44. }
  45. SHAR_EOF
  46. cat << \SHAR_EOF > regexp.3
  47. .TH REGEXP 3 local
  48. .DA 2 April 1986
  49. .SH NAME
  50. regcomp, regexec, regsub, regerror \- regular expression handler
  51. .SH SYNOPSIS
  52. .ft B
  53. .nf
  54. #include <regexp.h>
  55.  
  56. regexp *regcomp(exp)
  57. char *exp;
  58.  
  59. int regexec(prog, string)
  60. regexp *prog;
  61. char *string;
  62.  
  63. regsub(prog, source, dest)
  64. regexp *prog;
  65. char *source;
  66. char *dest;
  67.  
  68. regerror(msg)
  69. char *msg;
  70. .SH DESCRIPTION
  71. These functions implement
  72. .IR egrep (1)-style
  73. regular expressions and supporting facilities.
  74. .PP
  75. .I Regcomp
  76. compiles a regular expression into a structure of type
  77. .IR regexp ,
  78. and returns a pointer to it.
  79. The space has been allocated using
  80. .IR malloc (3)
  81. and may be released by
  82. .IR free .
  83. .PP
  84. .I Regexec
  85. matches a NUL-terminated \fIstring\fR against the compiled regular expression
  86. in \fIprog\fR.
  87. It returns 1 for success and 0 for failure, and adjusts the contents of
  88. \fIprog\fR's \fIstartp\fR and \fIendp\fR (see below) accordingly.
  89. .PP
  90. The members of a
  91. .I regexp
  92. structure include at least the following (not necessarily in order):
  93. .PP
  94. .RS
  95. char *startp[NSUBEXP];
  96. .br
  97. char *endp[NSUBEXP];
  98. .RE
  99. .PP
  100. where
  101. .I NSUBEXP
  102. is defined (as 10) in the header file.
  103. Once a successful \fIregexec\fR has been done using the \fIregexp\fR,
  104. each \fIstartp\fR-\fIendp\fR pair describes one substring
  105. within the \fIstring\fR,
  106. with the \fIstartp\fR pointing to the first character of the substring and
  107. the \fIendp\fR pointing to the first character following the substring.
  108. The 0th substring is the substring of \fIstring\fR that matched the whole
  109. regular expression.
  110. The others are those substrings that matched parenthesized expressions
  111. within the regular expression, with parenthesized expressions numbered
  112. in left-to-right order of their opening parentheses.
  113. .PP
  114. .I Regsub
  115. copies \fIsource\fR to \fIdest\fR, making substitutions according to the
  116. most recent \fIregexec\fR performed using \fIprog\fR.
  117. Each instance of `&' in \fIsource\fR is replaced by the substring
  118. indicated by \fIstartp\fR[\fI0\fR] and
  119. \fIendp\fR[\fI0\fR].
  120. Each instance of `\e\fIn\fR', where \fIn\fR is a digit, is replaced by
  121. the substring indicated by
  122. \fIstartp\fR[\fIn\fR] and
  123. \fIendp\fR[\fIn\fR].
  124. To get a literal `&' or `\e\fIn\fR' into \fIdest\fR, prefix it with `\e';
  125. to get a literal `\e' preceding `&' or `\e\fIn\fR', prefix it with
  126. another `\e'.
  127. .PP
  128. .I Regerror
  129. is called whenever an error is detected in \fIregcomp\fR, \fIregexec\fR,
  130. or \fIregsub\fR.
  131. The default \fIregerror\fR writes the string \fImsg\fR,
  132. with a suitable indicator of origin,
  133. on the standard
  134. error output
  135. and invokes \fIexit\fR(2).
  136. .I Regerror
  137. can be replaced by the user if other actions are desirable.
  138. .SH "REGULAR EXPRESSION SYNTAX"
  139. A regular expression is zero or more \fIbranches\fR, separated by `|'.
  140. It matches anything that matches one of the branches.
  141. .PP
  142. A branch is zero or more \fIpieces\fR, concatenated.
  143. It matches a match for the first, followed by a match for the second, etc.
  144. .PP
  145. A piece is an \fIatom\fR possibly followed by `*', `+', or `?'.
  146. An atom followed by `*' matches a sequence of 0 or more matches of the atom.
  147. An atom followed by `+' matches a sequence of 1 or more matches of the atom.
  148. An atom followed by `?' matches a match of the atom, or the null string.
  149. .PP
  150. An atom is a regular expression in parentheses (matching a match for the
  151. regular expression), a \fIrange\fR (see below), `.'
  152. (matching any single character), `^' (matching the null string at the
  153. beginning of the input string), `$' (matching the null string at the
  154. end of the input string), a `\e' followed by a single character (matching
  155. that character), or a single character with no other significance
  156. (matching that character).
  157. .PP
  158. A \fIrange\fR is a sequence of characters enclosed in `[]'.
  159. It normally matches any single character from the sequence.
  160. If the sequence begins with `^',
  161. it matches any single character \fInot\fR from the rest of the sequence.
  162. If two characters in the sequence are separated by `\-', this is shorthand
  163. for the full list of ASCII characters between them
  164. (e.g. `[0-9]' matches any decimal digit).
  165. To include a literal `]' in the sequence, make it the first character
  166. (following a possible `^').
  167. To include a literal `\-', make it the first or last character.
  168. .SH AMBIGUITY
  169. If a regular expression could match two different parts of the input string,
  170. it will match the one which begins earliest.
  171. If both begin in the same place    but match different lengths, or match
  172. the same length in different ways, life gets messier, as follows.
  173. .PP
  174. In general, the possibilities in a list of branches are considered in
  175. left-to-right order, the possibilities for `*', `+', and `?' are
  176. considered longest-first, nested constructs are considered from the
  177. outermost in, and concatenated constructs are considered leftmost-first.
  178. The match that will be chosen is the one that uses the earliest
  179. possibility in the first choice that has to be made.
  180. If there is more than one choice, the next will be made in the same manner
  181. (earliest possibility) subject to the decision on the first choice.
  182. And so forth.
  183. .PP
  184. For example, `(ab|a)b*c' could match `abc' in one of two ways.
  185. The first choice is between `ab' and `a'; since `ab' is earlier, and does
  186. lead to a successful overall match, it is chosen.
  187. Since the `b' is already spoken for,
  188. the `b*' must match its last possibility\(emthe empty string\(emsince
  189. it must respect the earlier choice.
  190. .PP
  191. In the particular case where no `|'s are present and there is only one
  192. `*', `+', or `?', the net effect is that the longest possible
  193. match will be chosen.
  194. So `ab*', presented with `xabbbby', will match `abbbb'.
  195. Note that if `ab*' is tried against `xabyabbbz', it
  196. will match `ab' just after `x', due to the begins-earliest rule.
  197. (In effect, the decision on where to start the match is the first choice
  198. to be made, hence subsequent choices must respect it even if this leads them
  199. to less-preferred alternatives.)
  200. .SH SEE ALSO
  201. egrep(1), expr(1)
  202. .SH DIAGNOSTICS
  203. \fIRegcomp\fR returns NULL for a failure
  204. (\fIregerror\fR permitting),
  205. where failures are syntax errors, exceeding implementation limits,
  206. or applying `+' or `*' to a possibly-null operand.
  207. .SH HISTORY
  208. Both code and manual page were
  209. written at U of T.
  210. They are intended to be compatible with the Bell V8 \fIregexp\fR(3),
  211. but are not derived from Bell code.
  212. .SH BUGS
  213. Empty branches and empty regular expressions are not portable to V8.
  214. .PP
  215. The restriction against
  216. applying `*' or `+' to a possibly-null operand is an artifact of the
  217. simplistic implementation.
  218. .PP
  219. Does not support \fIegrep\fR's newline-separated branches;
  220. neither does the V8 \fIregexp\fR(3), though.
  221. .PP
  222. Due to emphasis on
  223. compactness and simplicity,
  224. it's not strikingly fast.
  225. It does give special attention to handling simple cases quickly.
  226. SHAR_EOF
  227. cat << \SHAR_EOF > regexp.c
  228. /*
  229.  * regcomp and regexec -- regsub and regerror are elsewhere @(#)regexp.c 1.3
  230.  * of 18 April 87 
  231.  *
  232.  * Copyright (c) 1986 by University of Toronto. Written by Henry Spencer.  Not
  233.  * derived from licensed software. 
  234.  *
  235.  * Permission is granted to anyone to use this software for any purpose on any
  236.  * computer system, and to redistribute it freely, subject to the following
  237.  * restrictions: 
  238.  *
  239.  * 1. The author is not responsible for the consequences of use of this
  240.  * software, no matter how awful, even if they arise from defects in it. 
  241.  *
  242.  * 2. The origin of this software must not be misrepresented, either by explicit
  243.  * claim or by omission. 
  244.  *
  245.  * 3. Altered versions must be plainly marked as such, and must not be
  246.  * misrepresented as being the original software. 
  247.  *
  248.  * Beware that some of this code is subtly aware of the way operator precedence
  249.  * is structured in regular expressions.  Serious changes in
  250.  * regular-expression syntax might require a total rethink. 
  251.  */
  252. #include <stdio.h>
  253. #ifdef AMIGA
  254. #undef min
  255. #include "regexp.h"
  256. #else
  257. #include <regexp.h>
  258. #endif
  259. #include "regmagic.h"
  260.  
  261. /*
  262.  * The "internal use only" fields in regexp.h are present to pass info from
  263.  * compile to execute that permits the execute phase to run lots faster on
  264.  * simple cases.  They are: 
  265.  *
  266.  * regstart    char that must begin a match; '\0' if none obvious reganch
  267.  * is the match anchored (at beginning-of-line only)? regmust    string
  268.  * (pointer into program) that match must include, or NULL regmlen
  269.  * length of regmust string 
  270.  *
  271.  * Regstart and reganch permit very fast decisions on suitable starting points
  272.  * for a match, cutting down the work a lot.  Regmust permits fast rejection
  273.  * of lines that cannot possibly match.  The regmust tests are costly enough
  274.  * that regcomp() supplies a regmust only if the r.e. contains something
  275.  * potentially expensive (at present, the only such thing detected is * or +
  276.  * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  277.  * supplied because the test in regexec() needs it and regcomp() is computing
  278.  * it anyway. 
  279.  */
  280.  
  281. /*
  282.  * Structure for regexp "program".  This is essentially a linear encoding of
  283.  * a nondeterministic finite-state machine (aka syntax charts or "railroad
  284.  * normal form" in parsing technology).  Each node is an opcode plus a "next"
  285.  * pointer, possibly plus an operand.  "Next" pointers of all nodes except
  286.  * BRANCH implement concatenation; a "next" pointer with a BRANCH on both
  287.  * ends of it is connecting two alternatives.    (Here we have one of the
  288.  * subtle syntax dependencies:    an individual BRANCH (as opposed to a
  289.  * collection of them) is never concatenated with anything because of
  290.  * operator precedence.)  The operand of some types of node is a literal
  291.  * string; for others, it is a node leading into a sub-FSM.  In particular,
  292.  * the operand of a BRANCH node is the first node of the branch. (NB this is
  293.  * *not* a tree structure:  the tail of the branch connects to the thing
  294.  * following the set of BRANCHes.)  The opcodes are: 
  295.  */
  296.  
  297. /* definition    number    opnd?    meaning */
  298. #define END    0        /* no    End of program. */
  299. #define BOL    1        /* no    Match "" at beginning of line. */
  300. #define EOL    2        /* no    Match "" at end of line. */
  301. #define ANY    3        /* no    Match any one character. */
  302. #define ANYOF    4        /* str    Match any character in this string. */
  303. #define ANYBUT    5        /* str    Match any character not in this
  304.                  * string. */
  305. #define BRANCH    6        /* node Match this alternative, or the
  306.                  * next... */
  307. #define BACK    7        /* no    Match "", "next" ptr points backward. */
  308. #define EXACTLY 8        /* str    Match this string. */
  309. #define NOTHING 9        /* no    Match empty string. */
  310. #define STAR    10        /* node Match this (simple) thing 0 or more
  311.                  * times. */
  312. #define PLUS    11        /* node Match this (simple) thing 1 or more
  313.                  * times. */
  314. #define OPEN    20        /* no    Mark this point in input as start of
  315.                  * #n. */
  316. /* OPEN+1 is number 1, etc. */
  317. #define CLOSE    30        /* no    Analogous to OPEN. */
  318.  
  319. /*
  320.  * Opcode notes: 
  321.  *
  322.  * BRANCH    The set of branches constituting a single choice are hooked together
  323.  * with their "next" pointers, since precedence prevents anything being
  324.  * concatenated to any individual branch.  The "next" pointer of the last
  325.  * BRANCH in a choice points to the thing following the whole choice.  This
  326.  * is also where the final "next" pointer of each individual branch points;
  327.  * each branch starts with the operand node of a BRANCH node. 
  328.  *
  329.  * BACK     Normal "next" pointers all implicitly point forward; BACK exists to
  330.  * make loop structures possible. 
  331.  *
  332.  * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  333.  * BRANCH structures using BACK.  Simple cases (one character per match) are
  334.  * implemented with STAR and PLUS for speed and to minimize recursive
  335.  * plunges. 
  336.  *
  337.  * OPEN,CLOSE    ...are numbered at compile time. 
  338.  */
  339.  
  340. /*
  341.  * A node is one char of opcode followed by two chars of "next" pointer.
  342.  * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  343.  * value is a positive offset from the opcode of the node containing it. An
  344.  * operand, if any, simply follows the node.  (Note that much of the code
  345.  * generation knows about this implicit relationship.) 
  346.  *
  347.  * Using two bytes for the "next" pointer is vast overkill for most things, but
  348.  * allows patterns to get big without disasters. 
  349.  */
  350. #define OP(p)   (*(p))
  351. #define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  352. #define OPERAND(p)      ((p) + 3)
  353.  
  354. /*
  355.  * See regmagic.h for one further detail of program structure. 
  356.  */
  357.  
  358.  
  359. /*
  360.  * Utility definitions. 
  361.  */
  362. #ifndef CHARBITS
  363. #define UCHARAT(p)      ((int)*(unsigned char *)(p))
  364. #else
  365. #define UCHARAT(p)      ((int)*(p)&CHARBITS)
  366. #endif
  367.  
  368. #define FAIL(m) { regerror(m); return(NULL); }
  369. #define ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
  370. #define META    "^$.[()|?+*\\"
  371.  
  372. /*
  373.  * Flags to be passed up and down. 
  374.  */
  375. #define HASWIDTH    01    /* Known never to match null string. */
  376. #define SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  377. #define SPSTART     04    /* Starts with * or +. */
  378. #define WORST        0    /* Worst case. */
  379.  
  380. /*
  381.  * Global work variables for regcomp(). 
  382.  */
  383. static char    *regparse;    /* Input-scan pointer. */
  384. static int      regnpar;    /* () count. */
  385. static char     regdummy;
  386. static char    *regcode;    /* Code-emit pointer; ®dummy = don't. */
  387. static long     regsize;    /* Code size. */
  388.  
  389. /*
  390.  * Forward declarations for regcomp()'s friends. 
  391.  */
  392. #ifndef STATIC
  393. #define STATIC    static
  394. #endif
  395. STATIC char    *reg();
  396. STATIC char    *regbranch();
  397. STATIC char    *regpiece();
  398. STATIC char    *regatom();
  399. STATIC char    *regnode();
  400. STATIC char    *regnext();
  401. STATIC void     regc();
  402. STATIC void     reginsert();
  403. STATIC void     regtail();
  404. STATIC void     regoptail();
  405. #ifdef STRCSPN
  406. int             strcspn();
  407. #endif
  408.  
  409. /*
  410.  * - regcomp - compile a regular expression into internal code 
  411.  *
  412.  * We can't allocate space until we know how big the compiled form will be, but
  413.  * we can't compile it (and thus know how big it is) until we've got a place
  414.  * to put the code.  So we cheat:  we compile it twice, once with code
  415.  * generation turned off and size counting turned on, and once "for real".
  416.  * This also means that we don't allocate space until we are sure that the
  417.  * thing really will compile successfully, and we never have to move the code
  418.  * and thus invalidate pointers into it.  (Note that it has to be in one
  419.  * piece because free() must be able to free it all.) 
  420.  *
  421.  * Beware that the optimization-preparation code in here knows about some of the
  422.  * structure of the compiled regexp. 
  423.  */
  424. regexp         *
  425. regcomp(exp)
  426.     char           *exp;
  427. {
  428.     register regexp *r;
  429.     register char  *scan;
  430.     register char  *longest;
  431.     register int    len;
  432.     int             flags;
  433.     extern char    *malloc();
  434.  
  435.     if (exp == NULL)
  436.     FAIL("NULL argument");
  437.  
  438.     /* First pass: determine size, legality. */
  439.     regparse = exp;
  440.     regnpar = 1;
  441.     regsize = 0L;
  442.     regcode = ®dummy;
  443.     regc(MAGIC);
  444.     if (reg(0, &flags) == NULL)
  445.     return (NULL);
  446.  
  447.     /* Small enough for pointer-storage convention? */
  448.     if (regsize >= 32767L)    /* Probably could be 65535L. */
  449.     FAIL("regexp too big");
  450.  
  451.     /* Allocate space. */
  452.     r = (regexp *) malloc(sizeof(regexp) + (unsigned) regsize);
  453.     if (r == NULL)
  454.     FAIL("out of space");
  455.  
  456.     /* Second pass: emit code. */
  457.     regparse = exp;
  458.     regnpar = 1;
  459.     regcode = r->program;
  460.     regc(MAGIC);
  461.     if (reg(0, &flags) == NULL)
  462.     return (NULL);
  463.  
  464.     /* Dig out information for optimizations. */
  465.     r->regstart = '\0';        /* Worst-case defaults. */
  466.     r->reganch = 0;
  467.     r->regmust = NULL;
  468.     r->regmlen = 0;
  469.     scan = r->program + 1;    /* First BRANCH. */
  470.     if (OP(regnext(scan)) == END) {    /* Only one top-level choice. */
  471.     scan = OPERAND(scan);
  472.  
  473.     /* Starting-point info. */
  474.     if (OP(scan) == EXACTLY)
  475.         r->regstart = *OPERAND(scan);
  476.     else if (OP(scan) == BOL)
  477.         r->reganch++;
  478.  
  479.     /*
  480.      * If there's something expensive in the r.e., find the longest
  481.      * literal string that must appear and make it the regmust.  Resolve
  482.      * ties in favor of later strings, since the regstart check works
  483.      * with the beginning of the r.e. and avoiding duplication
  484.      * strengthens checking.  Not a strong reason, but sufficient in the
  485.      * absence of others. 
  486.      */
  487.     if (flags & SPSTART) {
  488.         longest = NULL;
  489.         len = 0;
  490.         for (; scan != NULL; scan = regnext(scan))
  491.         if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  492.             longest = OPERAND(scan);
  493.             len = strlen(OPERAND(scan));
  494.         }
  495.         r->regmust = longest;
  496.         r->regmlen = len;
  497.     }
  498.     }
  499.     return (r);
  500. }
  501.  
  502. /*
  503.  * - reg - regular expression, i.e. main body or parenthesized thing 
  504.  *
  505.  * Caller must absorb opening parenthesis. 
  506.  *
  507.  * Combining parenthesis handling with the base level of regular expression is a
  508.  * trifle forced, but the need to tie the tails of the branches to what
  509.  * follows makes it hard to avoid. 
  510.  */
  511. static char    *
  512. reg(paren, flagp)
  513.     int             paren;    /* Parenthesized? */
  514.     int            *flagp;
  515. {
  516.     register char  *ret;
  517.     register char  *br;
  518.     register char  *ender;
  519.     register int    parno;
  520.     int             flags;
  521.  
  522.     *flagp = HASWIDTH;        /* Tentatively. */
  523.  
  524.     /* Make an OPEN node, if parenthesized. */
  525.     if (paren) {
  526.     if (regnpar >= NSUBEXP)
  527.         FAIL("too many ()");
  528.     parno = regnpar;
  529.     regnpar++;
  530.     ret = regnode(OPEN + parno);
  531.     } else
  532.     ret = NULL;
  533.  
  534.     /* Pick up the branches, linking them together. */
  535.     br = regbranch(&flags);
  536.     if (br == NULL)
  537.     return (NULL);
  538.     if (ret != NULL)
  539.     regtail(ret, br);    /* OPEN -> first. */
  540.     else
  541.     ret = br;
  542.     if (!(flags & HASWIDTH))
  543.     *flagp &= ~HASWIDTH;
  544.     *flagp |= flags & SPSTART;
  545.     while (*regparse == '|') {
  546.     regparse++;
  547.     br = regbranch(&flags);
  548.     if (br == NULL)
  549.         return (NULL);
  550.     regtail(ret, br);    /* BRANCH -> BRANCH. */
  551.     if (!(flags & HASWIDTH))
  552.         *flagp &= ~HASWIDTH;
  553.     *flagp |= flags & SPSTART;
  554.     }
  555.  
  556.     /* Make a closing node, and hook it on the end. */
  557.     ender = regnode((paren) ? CLOSE + parno : END);
  558.     regtail(ret, ender);
  559.  
  560.     /* Hook the tails of the branches to the closing node. */
  561.     for (br = ret; br != NULL; br = regnext(br))
  562.     regoptail(br, ender);
  563.  
  564.     /* Check for proper termination. */
  565.     if (paren && *regparse++ != ')') {
  566.     FAIL("unmatched ()");
  567.     } else if (!paren && *regparse != '\0') {
  568.     if (*regparse == ')') {
  569.         FAIL("unmatched ()");
  570.     } else
  571.         FAIL("junk on end");/* "Can't happen". */
  572.     /* NOTREACHED */
  573.     }
  574.     return (ret);
  575. }
  576.  
  577. /*
  578.  * - regbranch - one alternative of an | operator 
  579.  *
  580.  * Implements the concatenation operator. 
  581.  */
  582. static char    *
  583. regbranch(flagp)
  584.     int            *flagp;
  585. {
  586.     register char  *ret;
  587.     register char  *chain;
  588.     register char  *latest;
  589.     int             flags;
  590.  
  591.     *flagp = WORST;        /* Tentatively. */
  592.  
  593.     ret = regnode(BRANCH);
  594.     chain = NULL;
  595.     while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  596.     latest = regpiece(&flags);
  597.     if (latest == NULL)
  598.         return (NULL);
  599.     *flagp |= flags & HASWIDTH;
  600.     if (chain == NULL)    /* First piece. */
  601.         *flagp |= flags & SPSTART;
  602.     else
  603.         regtail(chain, latest);
  604.     chain = latest;
  605.     }
  606.     if (chain == NULL)        /* Loop ran zero times. */
  607.     (void) regnode(NOTHING);
  608.  
  609.     return (ret);
  610. }
  611.  
  612. /*
  613.  * - regpiece - something followed by possible [*+?] 
  614.  *
  615.  * Note that the branching code sequences used for ? and the general cases of *
  616.  * and + are somewhat optimized:  they use the same NOTHING node as both the
  617.  * endmarker for their branch list and the body of the last branch. It might
  618.  * seem that this node could be dispensed with entirely, but the endmarker
  619.  * role is not redundant. 
  620.  */
  621. static char    *
  622. regpiece(flagp)
  623.     int            *flagp;
  624. {
  625.     register char  *ret;
  626.     register char   op;
  627.     register char  *next;
  628.     int             flags;
  629.  
  630.     ret = regatom(&flags);
  631.     if (ret == NULL)
  632.     return (NULL);
  633.  
  634.     op = *regparse;
  635.     if (!ISMULT(op)) {
  636.     *flagp = flags;
  637.     return (ret);
  638.     }
  639.     if (!(flags & HASWIDTH) && op != '?')
  640.     FAIL("*+ operand could be empty");
  641.     *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
  642.  
  643.     if (op == '*' && (flags & SIMPLE))
  644.     reginsert(STAR, ret);
  645.     else if (op == '*') {
  646.     /* Emit x* as (x&|), where & means "self". */
  647.     reginsert(BRANCH, ret);    /* Either x */
  648.     regoptail(ret, regnode(BACK));    /* and loop */
  649.     regoptail(ret, ret);    /* back */
  650.     regtail(ret, regnode(BRANCH));    /* or */
  651.     regtail(ret, regnode(NOTHING));    /* null. */
  652.     } else if (op == '+' && (flags & SIMPLE))
  653.     reginsert(PLUS, ret);
  654.     else if (op == '+') {
  655.     /* Emit x+ as x(&|), where & means "self". */
  656.     next = regnode(BRANCH);    /* Either */
  657.     regtail(ret, next);
  658.     regtail(regnode(BACK), ret);    /* loop back */
  659.     regtail(next, regnode(BRANCH));    /* or */
  660.     regtail(ret, regnode(NOTHING));    /* null. */
  661.     } else if (op == '?') {
  662.     /* Emit x? as (x|) */
  663.     reginsert(BRANCH, ret);    /* Either x */
  664.     regtail(ret, regnode(BRANCH));    /* or */
  665.     next = regnode(NOTHING);/* null. */
  666.     regtail(ret, next);
  667.     regoptail(ret, next);
  668.     }
  669.     regparse++;
  670.     if (ISMULT(*regparse))
  671.     FAIL("nested *?+");
  672.  
  673.     return (ret);
  674. }
  675.  
  676. /*
  677.  * - regatom - the lowest level 
  678.  *
  679.  * Optimization:  gobbles an entire sequence of ordinary characters so that it
  680.  * can turn them into a single node, which is smaller to store and faster to
  681.  * run.  Backslashed characters are exceptions, each becoming a separate
  682.  * node; the code is simpler that way and it's not worth fixing. 
  683.  */
  684. static char    *
  685. regatom(flagp)
  686.     int            *flagp;
  687. {
  688.     register char  *ret;
  689.     int             flags;
  690.  
  691.     *flagp = WORST;        /* Tentatively. */
  692.  
  693.     switch (*regparse++) {
  694.     case '^':
  695.     ret = regnode(BOL);
  696.     break;
  697.     case '$':
  698.     ret = regnode(EOL);
  699.     break;
  700.     case '.':
  701.     ret = regnode(ANY);
  702.     *flagp |= HASWIDTH | SIMPLE;
  703.     break;
  704.     case '[':{
  705.         register int    class;
  706.         register int    classend;
  707.  
  708.         if (*regparse == '^') {    /* Complement of range. */
  709.         ret = regnode(ANYBUT);
  710.         regparse++;
  711.         } else
  712.         ret = regnode(ANYOF);
  713.         if (*regparse == ']' || *regparse == '-')
  714.         regc(*regparse++);
  715.         while (*regparse != '\0' && *regparse != ']') {
  716.         if (*regparse == '-') {
  717.             regparse++;
  718.             if (*regparse == ']' || *regparse == '\0')
  719.             regc('-');
  720.             else {
  721.             class = UCHARAT(regparse - 2) + 1;
  722.             classend = UCHARAT(regparse);
  723.             if (class > classend + 1)
  724.                 FAIL("invalid [] range");
  725.             for (; class <= classend; class++)
  726.                 regc(class);
  727.             regparse++;
  728.             }
  729.         } else
  730.             regc(*regparse++);
  731.         }
  732.         regc('\0');
  733.         if (*regparse != ']')
  734.         FAIL("unmatched []");
  735.         regparse++;
  736.         *flagp |= HASWIDTH | SIMPLE;
  737.     }
  738.     break;
  739.     case '(':
  740.     ret = reg(1, &flags);
  741.     if (ret == NULL)
  742.         return (NULL);
  743.     *flagp |= flags & (HASWIDTH | SPSTART);
  744.     break;
  745.     case '\0':
  746.     case '|':
  747.     case ')':
  748.     FAIL("internal urp");    /* Supposed to be caught earlier. */
  749.     break;
  750.     case '?':
  751.     case '+':
  752.     case '*':
  753.     FAIL("?+* follows nothing");
  754.     break;
  755.     case '\\':
  756.     if (*regparse == '\0')
  757.         FAIL("trailing \\");
  758.     ret = regnode(EXACTLY);
  759.     regc(*regparse++);
  760.     regc('\0');
  761.     *flagp |= HASWIDTH | SIMPLE;
  762.     break;
  763.     default:{
  764.         register int    len;
  765.         register char   ender;
  766.  
  767.         regparse--;
  768.         len = strcspn(regparse, META);
  769.         if (len <= 0)
  770.         FAIL("internal disaster");
  771.         ender = *(regparse + len);
  772.         if (len > 1 && ISMULT(ender))
  773.         len--;        /* Back off clear of ?+* operand. */
  774.         *flagp |= HASWIDTH;
  775.         if (len == 1)
  776.         *flagp |= SIMPLE;
  777.         ret = regnode(EXACTLY);
  778.         while (len > 0) {
  779.         regc(*regparse++);
  780.         len--;
  781.         }
  782.         regc('\0');
  783.     }
  784.     break;
  785.     }
  786.  
  787.     return (ret);
  788. }
  789.  
  790. /*
  791.  * - regnode - emit a node 
  792.  */
  793. static char    *        /* Location. */
  794. regnode(op)
  795.     char            op;
  796. {
  797.     register char  *ret;
  798.     register char  *ptr;
  799.  
  800.     ret = regcode;
  801.     if (ret == ®dummy) {
  802.     regsize += 3;
  803.     return (ret);
  804.     }
  805.     ptr = ret;
  806.     *ptr++ = op;
  807.     *ptr++ = '\0';        /* Null "next" pointer. */
  808.     *ptr++ = '\0';
  809.     regcode = ptr;
  810.  
  811.     return (ret);
  812. }
  813.  
  814. /*
  815.  * - regc - emit (if appropriate) a byte of code 
  816.  */
  817. static void
  818. regc(b)
  819.     char            b;
  820. {
  821.     if (regcode != ®dummy)
  822.     *regcode++ = b;
  823.     else
  824.     regsize++;
  825. }
  826.  
  827. /*
  828.  * - reginsert - insert an operator in front of already-emitted operand 
  829.  *
  830.  * Means relocating the operand. 
  831.  */
  832. static void
  833. reginsert(op, opnd)
  834.     char            op;
  835.     char           *opnd;
  836. {
  837.     register char  *src;
  838.     register char  *dst;
  839.     register char  *place;
  840.  
  841.     if (regcode == ®dummy) {
  842.     regsize += 3;
  843.     return;
  844.     }
  845.     src = regcode;
  846.     regcode += 3;
  847.     dst = regcode;
  848.     while (src > opnd)
  849.     *--dst = *--src;
  850.  
  851.     place = opnd;        /* Op node, where operand used to be. */
  852.     *place++ = op;
  853.     *place++ = '\0';
  854.     *place++ = '\0';
  855. }
  856.  
  857. /*
  858.  * - regtail - set the next-pointer at the end of a node chain 
  859.  */
  860. static void
  861. regtail(p, val)
  862.     char           *p;
  863.     char           *val;
  864. {
  865.     register char  *scan;
  866.     register char  *temp;
  867.     register int    offset;
  868.  
  869.     if (p == ®dummy)
  870.     return;
  871.  
  872.     /* Find last node. */
  873.     scan = p;
  874.     for (;;) {
  875.     temp = regnext(scan);
  876.     if (temp == NULL)
  877.         break;
  878.     scan = temp;
  879.     }
  880.  
  881.     if (OP(scan) == BACK)
  882.     offset = scan - val;
  883.     else
  884.     offset = val - scan;
  885.     *(scan + 1) = (offset >> 8) & 0377;
  886.     *(scan + 2) = offset & 0377;
  887. }
  888.  
  889. /*
  890.  * - regoptail - regtail on operand of first argument; nop if operandless 
  891.  */
  892. static void
  893. regoptail(p, val)
  894.     char           *p;
  895.     char           *val;
  896. {
  897.     /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  898.     if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  899.     return;
  900.     regtail(OPERAND(p), val);
  901. }
  902.  
  903. /*
  904.  * regexec and friends 
  905.  */
  906.  
  907. /*
  908.  * Global work variables for regexec(). 
  909.  */
  910. static char    *reginput;    /* String-input pointer. */
  911. static char    *regbol;        /* Beginning of input, for ^ check. */
  912. static char   **regstartp;    /* Pointer to startp array. */
  913. static char   **regendp;    /* Ditto for endp. */
  914.  
  915. /*
  916.  * Forwards. 
  917.  */
  918. STATIC int      regtry();
  919. STATIC int      regmatch();
  920. STATIC int      regrepeat();
  921.  
  922. #ifdef DEBUG
  923. int             regnarrate = 0;
  924. void            regdump();
  925. STATIC char    *regprop();
  926. #endif
  927.  
  928. /*
  929.  * - regexec - match a regexp against a string 
  930.  */
  931. int
  932. regexec(prog, string)
  933.     register regexp *prog;
  934.     register char  *string;
  935. {
  936.     register char  *s;
  937.     extern char    *strchr();
  938.  
  939.     /* Be paranoid... */
  940.     if (prog == NULL || string == NULL) {
  941.     regerror("NULL parameter");
  942.     return (0);
  943.     }
  944.     /* Check validity of program. */
  945.     if (UCHARAT(prog->program) != MAGIC) {
  946.     regerror("corrupted program");
  947.     return (0);
  948.     }
  949.     /* If there is a "must appear" string, look for it. */
  950.     if (prog->regmust != NULL) {
  951.     s = string;
  952.     while ((s = strchr(s, prog->regmust[0])) != NULL) {
  953.         if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  954.         break;        /* Found it. */
  955.         s++;
  956.     }
  957.     if (s == NULL)        /* Not present. */
  958.         return (0);
  959.     }
  960.     /* Mark beginning of line for ^ . */
  961.     regbol = string;
  962.  
  963.     /* Simplest case:  anchored match need be tried only once. */
  964.     if (prog->reganch)
  965.     return (regtry(prog, string));
  966.  
  967.     /* Messy cases:  unanchored match. */
  968.     s = string;
  969.     if (prog->regstart != '\0')
  970.     /* We know what char it must start with. */
  971.     while ((s = strchr(s, prog->regstart)) != NULL) {
  972.         if (regtry(prog, s))
  973.         return (1);
  974.         s++;
  975.     }
  976.     else
  977.     /* We don't -- general case. */
  978.     do {
  979.         if (regtry(prog, s))
  980.         return (1);
  981.     } while (*s++ != '\0');
  982.  
  983.     /* Failure. */
  984.     return (0);
  985. }
  986.  
  987. /*
  988.  * - regtry - try match at specific point 
  989.  */
  990. static int            /* 0 failure, 1 success */
  991. regtry(prog, string)
  992.     regexp         *prog;
  993.     char           *string;
  994. {
  995.     register int    i;
  996.     register char **sp;
  997.     register char **ep;
  998.  
  999.     reginput = string;
  1000.     regstartp = prog->startp;
  1001.     regendp = prog->endp;
  1002.  
  1003.     sp = prog->startp;
  1004.     ep = prog->endp;
  1005.     for (i = NSUBEXP; i > 0; i--) {
  1006.     *sp++ = NULL;
  1007.     *ep++ = NULL;
  1008.     }
  1009.     if (regmatch(prog->program + 1)) {
  1010.     prog->startp[0] = string;
  1011.     prog->endp[0] = reginput;
  1012.     return (1);
  1013.     } else
  1014.     return (0);
  1015. }
  1016.  
  1017. /*
  1018.  * - regmatch - main matching routine 
  1019.  *
  1020.  * Conceptually the strategy is simple:  check to see whether the current node
  1021.  * matches, call self recursively to see whether the rest matches, and then
  1022.  * act accordingly.  In practice we make some effort to avoid recursion, in
  1023.  * particular by going through "ordinary" nodes (that don't need to know
  1024.  * whether the rest of the match failed) by a loop instead of by recursion. 
  1025.  */
  1026. static int            /* 0 failure, 1 success */
  1027. regmatch(prog)
  1028.     char           *prog;
  1029. {
  1030.     register char  *scan;    /* Current node. */
  1031.     char           *next;    /* Next node. */
  1032.     extern char    *strchr();
  1033.  
  1034.     scan = prog;
  1035. #ifdef DEBUG
  1036.     if (scan != NULL && regnarrate)
  1037.     fprintf(stderr, "%s(\n", regprop(scan));
  1038. #endif
  1039.     while (scan != NULL) {
  1040. #ifdef DEBUG
  1041.     if (regnarrate)
  1042.         fprintf(stderr, "%s...\n", regprop(scan));
  1043. #endif
  1044.     next = regnext(scan);
  1045.  
  1046.     switch (OP(scan)) {
  1047.     case BOL:
  1048.         if (reginput != regbol)
  1049.         return (0);
  1050.         break;
  1051.     case EOL:
  1052.         if (*reginput != '\0')
  1053.         return (0);
  1054.         break;
  1055.     case ANY:
  1056.         if (*reginput == '\0')
  1057.         return (0);
  1058.         reginput++;
  1059.         break;
  1060.     case EXACTLY:{
  1061.         register int    len;
  1062.         register char  *opnd;
  1063.  
  1064.         opnd = OPERAND(scan);
  1065.         /* Inline the first character, for speed. */
  1066.         if (*opnd != *reginput)
  1067.             return (0);
  1068.         len = strlen(opnd);
  1069.         if (len > 1 && strncmp(opnd, reginput, len) != 0)
  1070.             return (0);
  1071.         reginput += len;
  1072.         }
  1073.         break;
  1074.     case ANYOF:
  1075.         if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  1076.         return (0);
  1077.         reginput++;
  1078.         break;
  1079.     case ANYBUT:
  1080.         if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  1081.         return (0);
  1082.         reginput++;
  1083.         break;
  1084.     case NOTHING:
  1085.         break;
  1086.     case BACK:
  1087.         break;
  1088.     case OPEN + 1:
  1089.     case OPEN + 2:
  1090.     case OPEN + 3:
  1091.     case OPEN + 4:
  1092.     case OPEN + 5:
  1093.     case OPEN + 6:
  1094.     case OPEN + 7:
  1095.     case OPEN + 8:
  1096.     case OPEN + 9:{
  1097.         register int    no;
  1098.         register char  *save;
  1099.  
  1100.         no = OP(scan) - OPEN;
  1101.         save = reginput;
  1102.  
  1103.         if (regmatch(next)) {
  1104.             /*
  1105.              * Don't set startp if some later invocation of the same
  1106.              * parentheses already has. 
  1107.              */
  1108.             if (regstartp[no] == NULL)
  1109.             regstartp[no] = save;
  1110.             return (1);
  1111.         } else
  1112.             return (0);
  1113.         }
  1114.         break;
  1115.     case CLOSE + 1:
  1116.     case CLOSE + 2:
  1117.     case CLOSE + 3:
  1118.     case CLOSE + 4:
  1119.     case CLOSE + 5:
  1120.     case CLOSE + 6:
  1121.     case CLOSE + 7:
  1122.     case CLOSE + 8:
  1123.     case CLOSE + 9:{
  1124.         register int    no;
  1125.         register char  *save;
  1126.  
  1127.         no = OP(scan) - CLOSE;
  1128.         save = reginput;
  1129.  
  1130.         if (regmatch(next)) {
  1131.             /*
  1132.              * Don't set endp if some later invocation of the same
  1133.              * parentheses already has. 
  1134.              */
  1135.             if (regendp[no] == NULL)
  1136.             regendp[no] = save;
  1137.             return (1);
  1138.         } else
  1139.             return (0);
  1140.         }
  1141.         break;
  1142.     case BRANCH:{
  1143.         register char  *save;
  1144.  
  1145.         if (OP(next) != BRANCH)    /* No choice. */
  1146.             next = OPERAND(scan);    /* Avoid recursion. */
  1147.         else {
  1148.             do {
  1149.             save = reginput;
  1150.             if (regmatch(OPERAND(scan)))
  1151.                 return (1);
  1152.             reginput = save;
  1153.             scan = regnext(scan);
  1154.             } while (scan != NULL && OP(scan) == BRANCH);
  1155.             return (0);
  1156.             /* NOTREACHED */
  1157.         }
  1158.         }
  1159.         break;
  1160.     case STAR:
  1161.     case PLUS:{
  1162.         register char   nextch;
  1163.         register int    no;
  1164.         register char  *save;
  1165.         register int    min;
  1166.  
  1167.         /*
  1168.          * Lookahead to avoid useless match attempts when we know
  1169.          * what character comes next. 
  1170.          */
  1171.         nextch = '\0';
  1172.         if (OP(next) == EXACTLY)
  1173.             nextch = *OPERAND(next);
  1174.         min = (OP(scan) == STAR) ? 0 : 1;
  1175.         save = reginput;
  1176.         no = regrepeat(OPERAND(scan));
  1177.         while (no >= min) {
  1178.             /* If it could work, try it. */
  1179.             if (nextch == '\0' || *reginput == nextch)
  1180.             if (regmatch(next))
  1181.                 return (1);
  1182.             /* Couldn't or didn't -- back up. */
  1183.             no--;
  1184.             reginput = save + no;
  1185.         }
  1186.         return (0);
  1187.         }
  1188.         break;
  1189.     case END:
  1190.         return (1);        /* Success! */
  1191.         break;
  1192.     default:
  1193.         regerror("memory corruption");
  1194.         return (0);
  1195.         break;
  1196.     }
  1197.  
  1198.     scan = next;
  1199.     }
  1200.  
  1201.     /*
  1202.      * We get here only if there's trouble -- normally "case END" is the
  1203.      * terminating point. 
  1204.      */
  1205.     regerror("corrupted pointers");
  1206.     return (0);
  1207. }
  1208.  
  1209. /*
  1210.  * - regrepeat - repeatedly match something simple, report how many 
  1211.  */
  1212. static int
  1213. regrepeat(p)
  1214.     char           *p;
  1215. {
  1216.     register int    count = 0;
  1217.     register char  *scan;
  1218.     register char  *opnd;
  1219.  
  1220.     scan = reginput;
  1221.     opnd = OPERAND(p);
  1222.     switch (OP(p)) {
  1223.     case ANY:
  1224.     count = strlen(scan);
  1225.     scan += count;
  1226.     break;
  1227.     case EXACTLY:
  1228.     while (*opnd == *scan) {
  1229.         count++;
  1230.         scan++;
  1231.     }
  1232.     break;
  1233.     case ANYOF:
  1234.     while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1235.         count++;
  1236.         scan++;
  1237.     }
  1238.     break;
  1239.     case ANYBUT:
  1240.     while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1241.         count++;
  1242.         scan++;
  1243.     }
  1244.     break;
  1245.     default:            /* Oh dear.  Called inappropriately. */
  1246.     regerror("internal foulup");
  1247.     count = 0;        /* Best compromise. */
  1248.     break;
  1249.     }
  1250.     reginput = scan;
  1251.  
  1252.     return (count);
  1253. }
  1254.  
  1255. /*
  1256.  * - regnext - dig the "next" pointer out of a node 
  1257.  */
  1258. static char    *
  1259. regnext(p)
  1260.     register char  *p;
  1261. {
  1262.     register int    offset;
  1263.  
  1264.     if (p == ®dummy)
  1265.     return (NULL);
  1266.  
  1267.     offset = NEXT(p);
  1268.     if (offset == 0)
  1269.     return (NULL);
  1270.  
  1271.     if (OP(p) == BACK)
  1272.     return (p - offset);
  1273.     else
  1274.     return (p + offset);
  1275. }
  1276.  
  1277. #ifdef DEBUG
  1278.  
  1279. STATIC char    *regprop();
  1280.  
  1281. /*
  1282.  * - regdump - dump a regexp onto stdout in vaguely comprehensible form 
  1283.  */
  1284. void
  1285. regdump(r)
  1286.     regexp         *r;
  1287. {
  1288.     register char  *s;
  1289.     register char   op = EXACTLY;    /* Arbitrary non-END op. */
  1290.     register char  *next;
  1291.     extern char    *strchr();
  1292.  
  1293.  
  1294.     s = r->program + 1;
  1295.     while (op != END) {        /* While that wasn't END last time... */
  1296.     op = OP(s);
  1297.     printf("%2d%s", s - r->program, regprop(s));    /* Where, what. */
  1298.     next = regnext(s);
  1299.     if (next == NULL)    /* Next ptr. */
  1300.         printf("(0)");
  1301.     else
  1302.         printf("(%d)", (s - r->program) + (next - s));
  1303.     s += 3;
  1304.     if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1305.         /* Literal string, where present. */
  1306.         while (*s != '\0') {
  1307.         putchar(*s);
  1308.         s++;
  1309.         }
  1310.         s++;
  1311.     }
  1312.     putchar('\n');
  1313.     }
  1314.  
  1315.     /* Header fields of interest. */
  1316.     if (r->regstart != '\0')
  1317.     printf("start `%c' ", r->regstart);
  1318.     if (r->reganch)
  1319.     printf("anchored ");
  1320.     if (r->regmust != NULL)
  1321.     printf("must have \"%s\"", r->regmust);
  1322.     printf("\n");
  1323. }
  1324.  
  1325. /*
  1326.  * - regprop - printable representation of opcode 
  1327.  */
  1328. static char    *
  1329. regprop(op)
  1330.     char           *op;
  1331. {
  1332.     register char  *p;
  1333.     static char     buf[50];
  1334.  
  1335.     (void) strcpy(buf, ":");
  1336.  
  1337.     switch (OP(op)) {
  1338.     case BOL:
  1339.     p = "BOL";
  1340.     break;
  1341.     case EOL:
  1342.     p = "EOL";
  1343.     break;
  1344.     case ANY:
  1345.     p = "ANY";
  1346.     break;
  1347.     case ANYOF:
  1348.     p = "ANYOF";
  1349.     break;
  1350.     case ANYBUT:
  1351.     p = "ANYBUT";
  1352.     break;
  1353.     case BRANCH:
  1354.     p = "BRANCH";
  1355.     break;
  1356.     case EXACTLY:
  1357.     p = "EXACTLY";
  1358.     break;
  1359.     case NOTHING:
  1360.     p = "NOTHING";
  1361.     break;
  1362.     case BACK:
  1363.     p = "BACK";
  1364.     break;
  1365.     case END:
  1366.     p = "END";
  1367.     break;
  1368.     case OPEN + 1:
  1369.     case OPEN + 2:
  1370.     case OPEN + 3:
  1371.     case OPEN + 4:
  1372.     case OPEN + 5:
  1373.     case OPEN + 6:
  1374.     case OPEN + 7:
  1375.     case OPEN + 8:
  1376.     case OPEN + 9:
  1377.     sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
  1378.     p = NULL;
  1379.     break;
  1380.     case CLOSE + 1:
  1381.     case CLOSE + 2:
  1382.     case CLOSE + 3:
  1383.     case CLOSE + 4:
  1384.     case CLOSE + 5:
  1385.     case CLOSE + 6:
  1386.     case CLOSE + 7:
  1387.     case CLOSE + 8:
  1388.     case CLOSE + 9:
  1389.     sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
  1390.     p = NULL;
  1391.     break;
  1392.     case STAR:
  1393.     p = "STAR";
  1394.     break;
  1395.     case PLUS:
  1396.     p = "PLUS";
  1397.     break;
  1398.     default:
  1399.     regerror("corrupted opcode");
  1400.     break;
  1401.     }
  1402.     if (p != NULL)
  1403.     (void) strcat(buf, p);
  1404.     return (buf);
  1405. }
  1406. #endif
  1407.  
  1408. /*
  1409.  * The following is provided for those people who do not have strcspn() in
  1410.  * their C libraries.  They should get off their butts and do something about
  1411.  * it; at least one public-domain implementation of those (highly useful)
  1412.  * string routines has been published on Usenet. 
  1413.  */
  1414. #ifdef STRCSPN
  1415. /*
  1416.  * strcspn - find length of initial segment of s1 consisting entirely of
  1417.  * characters not from s2 
  1418.  */
  1419.  
  1420. static int
  1421. strcspn(s1, s2)
  1422.     char           *s1;
  1423.     char           *s2;
  1424. {
  1425.     register char  *scan1;
  1426.     register char  *scan2;
  1427.     register int    count;
  1428.  
  1429.     count = 0;
  1430.     for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1431.     for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1432.         if (*scan1 == *scan2++)
  1433.         return (count);
  1434.     count++;
  1435.     }
  1436.     return (count);
  1437. }
  1438. #endif
  1439. SHAR_EOF
  1440. cat << \SHAR_EOF > regexp.h
  1441. /*
  1442.  * Definitions etc. for regexp(3) routines.
  1443.  *
  1444.  * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  1445.  * not the System V one.
  1446.  */
  1447. #define NSUBEXP  10
  1448. typedef struct regexp {
  1449.     char *startp[NSUBEXP];
  1450.     char *endp[NSUBEXP];
  1451.     char regstart;        /* Internal use only. */
  1452.     char reganch;        /* Internal use only. */
  1453.     char *regmust;        /* Internal use only. */
  1454.     int regmlen;        /* Internal use only. */
  1455.     char program[1];    /* Unwarranted chumminess with compiler. */
  1456. } regexp;
  1457.  
  1458. extern regexp *regcomp();
  1459. extern int regexec();
  1460. extern void regsub();
  1461. extern void regerror();
  1462. SHAR_EOF
  1463. cat << \SHAR_EOF > regexp.lib.uue
  1464. begin 644 regexp.lib
  1465. M   #^@  !?$   /I    #$Y5  "_[   90   "\M  A(;   2&P 1$ZZ  !/
  1466. M[P ,2'@  4ZZ  !83TY=3G4      _@    !     0   !(        #[X8 
  1467. M  )?7V)A<V4       $    &@P   E]?>&-O=F8      0    J&   "7U]I
  1468. M;V(        !    %H,   )?9G!R:6YT9@    $    :@P   E]E>&ET    
  1469. M     0   "8        #\@   ^H    $<F5G97AP*#,I.B E<P       _( 
  1470. M  /I    14Y5_^Y(YP<PO^P  &4   !*K0 (9PQ*K0 ,9P9*K0 09@Y(;   
  1471. M3KH  %A/8   WG!:<@ @;0 ($C (  R!    G&<.2&P %$ZZ  !83V   +PF
  1472. M;0 ,)&T $!X34HM*!V<  *8,!P F9@1\ & F# < 7&8>$A,, 0 P;18, 0 Y
  1473. M;A!(@4C!4HL$@0   # L 6 "?/]*AFH># < 7&82$A,, 0!<9P8, 0 F9@0N
  1474. M 5*+%(=2BF"D( 8B!N6!(&T "$JP& !GE$JP&"AGCB &(@;E@2 P&"B0L!@ 
  1475. M*@ O!2\P&  O"DZZ  !/[P ,U<5*A6< _VA**O__9@#_8$AL #).N@  6$]@
  1476. M!$(24HI,WPS@3EU.=0   _@    #     0   /X   !&    )         /O
  1477. MA@   E]?8F%S90       0    J#   "7U]X8V]V9@     !    #H,   -?
  1478. M<F5G97)R;W(        #   ! @   $H    H@P   E]S=')N8W!Y     0  
  1479. M .8        #\@   ^H    23E5,3"!P87)M('1O(')E9W-U8@!D86UA9V5D
  1480. M(')E9V5X<"!F960@=&\@<F5G<W5B  !D86UA9V5D(&UA=&-H('-T<FEN9P  
  1481. M   #\@   ^D   0+3E7_[$CG 3"_[   90   $JM  AF$$AL  !.N@  6$]P
  1482. M &   50I;0 (  !P 2E   1"K  .0>P "$AX )PI2  *80 (M%A/2&W_[$*G
  1483. M80 !,%!/2H!F!G  8  !' RL  !__P .;1!(;  .3KH  %A/< !@  $"("P 
  1484. M#@:     7"\ 3KH  %A/)D"V_   9A!(;  >3KH  %A/< !@  #8*6T "   
  1485. M< $I0  $($O0_ !:2'@ G"E(  IA  @Z6$](;?_L0J=A  "V4$]*@&8&< !@
  1486. M  "B<  70 !0%T  49'()T@ 4B=( %8@2]#\ %LD2"\*80 .QEA/($ 2$$H!
  1487. M9G)6BA(2# $ "&8(%VH  P!08 A3 68$4BL 40@M  +_[V=0D<@N""M(__2T
  1488. M_   9S@,$@ (9B8@2B!*5H@O"$ZZ  !83["';10@2B!*5H@O""M(__1.N@  
  1489. M6$\N "\*80 .6EA/)$!@PB=M__0 4B=' %8@"TS?#(!.74YU3E7_[$CG 3"_
  1490. M[   90   ' !(&T #"" 2JT "&<X#*P    *  1M$$AL "Q.N@  6$]P &  
  1491. M 60N+  $4JP !" '( <&@    !0O &$ !N983R9 8 *7RTAM_^QA  %$6$\D
  1492. M0+3\  !F!G  8  !++;\  !G#"\*+PMA  >*4$]@ B9*""T  /_O9@H@;0 ,
  1493. M"*@    #("W_[ *     !"!M  R!D"!L   ,$ !\9DI2K   2&W_[&$  .A8
  1494. M3R1 M/P  &8&< !@  #0+PHO"V$ !S103P@M  #_[V8*(&T # BH     R M
  1495. M_^P"@     0@;0 ,@9!@K$JM  AG#" '( <&@    !Y@ G  +P!A  8B6$\O
  1496. M "\+*T#_]&$ !N903R1+M/P  &<8+RW_]"\*80 '1%!/+PIA  T"6$\D0&#B
  1497. M2JT "&<>(&P  ! 04JP   P  "EG#DAL #A.N@  6$]P & R2JT "&8J(&P 
  1498. M $H09R(,$  I9@Y(; !&3KH  %A/< !@$$AL %1.N@  6$]P & "( M,WPR 
  1499. M3EU.=4Y5__!(YP PO^P  &4    @;0 (0I!(>  &80 %=EA/)D"5RB!L  !*
  1500. M$&=:$A , 0!\9U(, 0 I9TQ(;?_P86!83RM __1*@&8$< !@2B M__ B  *!
  1501. M     2!M  B#D+3\  !F#B M__ "@     2!D& ,+RW_]"\*80 %Z%!/)&W_
  1502. M]&">M/P  &8*2'@ "6$ !0!83R +3-\, $Y=3G5.5?_R2.<!,+_L  !E    
  1503. M2&W_\F$  =983R9 MOP  &8&< !@  &^(&P  !X0# < *F<<# < *V<6# < 
  1504. M/V<0("W_\B)M  @B@" +8  !E@@M  #_]686# < /V<02&P 8$ZZ  !83W  
  1505. M8  !> P' "MG!' $8 )P 2!M  @@@ P' "IF& @M  '_]6<0+PM(>  *80 $
  1506. MS%!/8  !' P' "IF5B\+2'@ !F$ !+903TAX  =A  0\6$\O "\+80 %=E!/
  1507. M+PLO"V$ !6Q03TAX  9A  0>6$\O "\+80 $YE!/2'@ "6$ ! I83R\ +PMA
  1508. M  324$]@  # # < *V88""T  ?_U9Q O"TAX  MA  124$]@  "B# < *V94
  1509. M2'@ !F$  \Y83R1 +PHO"V$ !)103TAX  =A  .X6$\O"R\ 80 $@%!/2'@ 
  1510. M!F$  Z183R\ +PIA  1L4$](>  )80 #D%A/+P O"V$ !%A03V!&# < /V9 
  1511. M+PM(>  &80 #XE!/2'@ !F$  VA83R\ +PMA  0P4$](>  )80 #5%A/)$ O
  1512. M"B\+80 $&E!/+PHO"V$ !()03U*L   @;   $A , 0 J9PP, 0 K9P8, 0 _
  1513. M9@Y(; !Z3KH  %A/< !@ B +3-\,@$Y=3G5.5?_P2.</$+_L  !E    (&T 
  1514. M"$*0(&P  ! 02(!2K   <DA=06L  D*P>Q (9O1.^Q $ %Q@  'B "I@  ',
  1515. M "M@  '& #]@  '  "E@  &J 'Q@  &D  !@  &> "A@  %H %M@  !. "Y@
  1516. M   N "1@   8 %Y@   "2'@  6$  H183R9 8  "<DAX  )A  )T6$\F0&  
  1517. M F)(>  #80 "9%A/)D @;0 ( )     #8  "2"!L   ,$ !>9A)(>  %80 "
  1518. M0%A/)D!2K   8 Q(>  $80 "+EA/)D @;   $A , 0!=9P8, 0 M9A!(@4C!
  1519. M4JP  "\!80 "3EA/(&P  $H09P  CA(0# $ 76<  (0, 0 M9F)2K   (&P 
  1520. M !(0# $ 76<$2@%F#$AX "UA  (66$]@QE6(<  0$%* +@!\ "!L   <$" &
  1521. M( 92@+Z ;Q!(; "&3KH  %A/< !@  &:OH9N#"\'80 !W%A/4H=@\%*L  !@
  1522. MA"!L   0$$B 2,!2K   +P!A  &\6$]@ /]L0J=A  &P6$\@;   #!  76<0
  1523. M2&P F$ZZ  !83W  8  !2%*L   @;0 ( )     #8  !-$AM__A(>  !80#Y
  1524. M_E!/)D"V_   9@9P &   1H@+?_X H     %(&T "(&08  !!$AL *9.N@  
  1525. M6$]P &   /9(; "T3KH  %A/< !@  #F(&P  $H09A!(; #(3KH  %A/< !@
  1526. M  #.2'@ "&$  ,Y83R9 (&P  ! 02(!(P%*L   O &$  /I83T*G80  \EA/
  1527. M(&T " "0     V   )13K   2&P U"\L  !.N@  4$\J $J%;@Y(; #@3KH 
  1528. M %A/< !@;B!L   8,%@ #(4    !;Q0,!  J9PP,!  K9P8,!  _9@)3A2!M
  1529. M  @(Z     ,,A0    %F!@CH  $  TAX  AA-%A/)D!*A6\:(&P  ! 02(!(
  1530. MP%*L   O &$  %Y83U.%8.)"IV$  %)83R +3-\(\$Y=3G5.5?_X2.< ,+_L
  1531. M  !E    )FP "D'L  BQRV8(5JP #B +8!@D2Q2M  M2BG  %(!2BA2 4HHI
  1532. M2@ *( M,WPP 3EU.=4Y5  "_[   90   $'L  @B+  *L<%G#"!!$*T "U*L
  1533. M  I@!%*L  Y.74YU3E7_]$CG #"_[   90   $'L  @B+  *L<%F!E:L  Y@
  1534. M."9!5JP "B1L  JW[0 ,8PA3BE.+%)-@\B!M  P0K0 +*TC_]%*(<  0@"M(
  1535. M__12B!" *TC_]%*(3-\, $Y=3G5.5?_T2.<!,+_L  !E    0>P ""(M  BQ
  1536. MP6=.)D$O"V$ !A983R1 M/P  &<$)DI@[ P3  =F"B +D*T #"X 8 H@+0 ,
  1537. M(@N0@2X ( <B!^"! H$   #_%T$  2 '( <"@    /\70  "3-\,@$Y=3G5.
  1538. M50  O^P  &4   !*K0 (9R9![  ((BT "+'!9QH@00P0  9F$B!M  A6B"\M
  1539. M  PO"&$ _UI03TY=3G5.5?_\2.< ,+_L  !E    )FT ""1M  RV_   9P:T
  1540. M_   9A!(; #R3KH  %A/< !@  #B<%IR !(S"  ,@0   )QG$$AL 0).N@  
  1541. M6$]P &   ,)*JP!29T@K2O_\(&L 4A 02(!(P"\ +RW__$ZZ  !03RM __Q*
  1542. M@&<<+RL 5B\K %(O $ZZ  !/[P ,2H!G!E*M__Q@QDJM__QF!'  8'(I2@ 6
  1543. M2BL 46<*+PHO"V%J4$]@7BM*__Q**P!09S(0*P!02(!(P"\ +RW__$ZZ  !0
  1544. M3RM __Q*@&<V+P O"V$Z4$]*@&<$< %@*%*M__Q@SB\M__PO"V$B4$]*@&<$
  1545. M< %@$"!M__P0$%*M__Q* &;@< !,WPP 3EU.=4Y5__1(YP$PO^P  &4    I
  1546. M;0 , !(@;0 (*4@ &M#\ "@F;0 ((FT "-+\ "@D27X**4@ 'DJ';PZ1R":(
  1547. M6(LDB%B*4X=@[B!M  C0_ !;+PAA)%A/2H!G$B!M  @@K0 ,(6P $@ H< %@
  1548. M!'  3G%,WPR 3EU.=4Y5_^I(YP\PO^P  &4    F;0 (MOP  &<  Q0O"V$ 
  1549. M ]983Q(32($K0/_X#$$ *&0  N;E04[[$ )@  +88   FF   *A@  "T8  !
  1550. M$F   3Y@  'R8  "SF   +9@  +&8  ".F   C9@  *L8  "J&   J1@  *@
  1551. M8  "G&   IA@  *48  "D&   HQ@  $N8  !*F   29@  $B8  !'F   1I@
  1552. M  $68  !$F   0Y@  )D8  !2F   49@  %"8  !/F   3I@  $V8  !,F  
  1553. M 2Y@  $J(&P $K'L !9G  )"< !@  )0(&P $DH09P ",G  8  "0"!L !)*
  1554. M$&8&< !@  (R4JP $F   A8@2R!+5H@D2!(2(&P $K(09P9P &   A(O"DZZ
  1555. M  !83RX #(<    !;QHO!R\L !(O"DZZ  !/[P ,2H!G!G  8  !YM^L !)@
  1556. M  '*(&P $DH09QHB2R)+5HD0$$B 2, O "\)3KH  %!/2H!F!G  8  !ME*L
  1557. M !)@  &:(&P $DH09QHB2R)+5HD0$$B 2, O "\)3KH  %!/2H!G!G  8  !
  1558. MAE*L !)@  %J$!-(@$C !(     4+  K;  2__ O+?_X80#^*%A/2H!G'" &
  1559. M(@;E@2!L !I*L!@ 9@8AK?_P& !P 6   4!P &   3H0$TB 2, $@    !XJ
  1560. M "ML !+_\"\M__AA /WD6$]*@&<<( 4B!>6!(&P 'DJP& !F!B&M__ 8 ' !
  1561. M8   _'  8   ]B!M__@,$  &9PX@2R!+5H@K2/_X8   RBML !+_]"!+($M6
  1562. MB"\(80#]DEA/2H!G!G !8   P"EM__0 $B\+80 !<%A/)D"V_   9P8,$P &
  1563. M9\9P &   )YX "!M__@,$  (9@08*  ##!, "F8$< !@ G !*VP $O_N($L@
  1564. M2U:(+P@K0/_J87183RM __(B+?_RLJW_ZFTR2@1G"B!L !(2$+($9A(O+?_X
  1565. M80#]#EA/2H!G!' !8#Q3K?_R(&W_[M'M__(I2  28,1P & F< %@(DAL 11.
  1566. MN@  6$]P & 4)FW_^&  _.A(; $F3KH  %A/< !,WPSP3EU.=4Y5__1(YP$P
  1567. MO^P  &4   !^ "9L !(@;0 (5H@D2"!M  @0$$B !$   VUN#$  !FQHXT!.
  1568. M^P "8 I@(F ^8%I@6& .+PM.N@  6$\N -?'8%02$K(39DY2AU*+8/1*$V=$
  1569. M$!-(@$C +P O"DZZ  !03TJ 9S!2AU*+8.)*$V<F$!-(@$C +P O"DZZ  !0
  1570. M3TJ 9A)2AU*+8.)(; $Z3KH  %A/?@ I2P 2( =,WPR 3EU.=4Y5__Q(YP$0
  1571. MO^P  &4    F;0 (0>P "+'+9@1P &!$$"L  4B 2, "@    /_A@!(K  )(
  1572. M@4C! H$   #_T($N $J'9@1P & :#!, !V8*($L@2Y''( A@"B!+($O1QR (
  1573. M3G%,WPB 3EU.=0     #^    !4    !   /I@  #O@   [B   *>@  "EH 
  1574. M  @R   ('@  !](   >Z   'J@  !U@   <&   %F   !"(   ,,   "_@  
  1575. M MP   &J    E    &H    8    60    (   _4   /L@  #QX   [4   .
  1576. MK   #H0   Y(   .*   #?0   W:   -L   #98   V    -6   #5    TH
  1577. M   -(   #0@   SF   ,U   #,8   RV   ,J   #*0   NT   +A   "VP 
  1578. M  MD   *V   "@P   F8   )3@  "4H   E"   ).@  "38   D>   )&   
  1579. M"0H   D&   ([   "-(   C*   (Q@  ")0   B*   (0   ""(   @:   '
  1580. M^   !^X   ?*   ':   !TX   <V   '+   !R8   ;V   &S@  !LH   :P
  1581. M   &I   !HX   9\   &9@  !<X   7&   %@   !7P   /L   #2    O  
  1582. M  +2   "S    C(   (H   !O@   ;H   &D    N@   *P   "F    >@  
  1583. M &0   !     .    #0    P    *@        /OA@   E]?8F%S90      
  1584. M#P  #\@   \4   +T@  "UH   H^   )_@  "9    DN   (_@  "+X   6X
  1585. M   #S    RP   &*    "H,   )?7WAC;W9F      \   _,   /&   "]8 
  1586. M  M>   *0@  "@(   F4   ),@  "0(   C"   %O    ]    ,P   !C@  
  1587. M  Z#   #7W)E9V5R<F]R        %   #ZH   [\   .Y@  "GX   I>   (
  1588. M-@  !]8   >^   'K@  !UP   <*   %G   !"8   ,0   # @   N    &N
  1589. M    F    &X    <@P   E]M86QL;V,      0   (:#   "7W-T<FQE;@  
  1590. M   $   /4@  #/8   %:   !1(,   )?<W1R8W-P;@    $   @F@P   E]S
  1591. M=')C:'(     !@  #Y8   ]X   -<   #4    L$   *I(,   )?<W1R;F-M
  1592. M<     (   T.   *O         /R   #Z@   %-.54Q,(&%R9W5M96YT ')E
  1593. M9V5X<"!T;V\@8FEG  !O=70@;V8@<W!A8V4  '1O;R!M86YY("@I '5N;6%T
  1594. M8VAE9" H*0  =6YM871C:&5D("@I  !J=6YK(&]N(&5N9  J*R!O<&5R86YD
  1595. M(&-O=6QD(&)E(&5M<'1Y &YE<W1E9" J/RL  &EN=F%L:60@6UT@<F%N9V4 
  1596. M '5N;6%T8VAE9"!;70  :6YT97)N86P@=7)P   _*RH@9F]L;&]W<R!N;W1H
  1597. M:6YG '1R86EL:6YG(%P  %XD+ELH*7P_*RI< &EN=&5R;F%L(&1I<V%S=&5R
  1598. M $Y53$P@<&%R86UE=&5R  !C;W)R=7!T960@<')O9W)A;0!M96UO<GD@8V]R
  1599. M<G5P=&EO;@!C;W)R=7!T960@<&]I;G1E<G,  &EN=&5R;F%L(&9O=6QU<   
  1600. M     _(   /K    "0   _(   /[    3@"B ')E9V5R<F]R+F\ 7V5X:70 
  1601. M7V9P<FEN=&8 7U]I;V( 7U]X8V]V9@!?7V)A<V4 7W)E9V5R<F]R %]?3452
  1602. M1T5$ ')E9W-U8BYO %]S=')N8W!Y %]R96=S=6( <F5G97AP+F\ 7W-T<FYC
  1603. M;7  7W-T<F-H<@!?<W1R8W-P;@!?<W1R;&5N %]M86QL;V, 7W)E9V5X96, 
  1604. M7W)E9V-O;7    $    "    # /I  4 "P 1 !H (  H  $ ,     $ .@ $
  1605. M ^H      $, -@ "    10/I  0 2P O "  *  ! %4    ! #H $@/J    
  1606. M  != +,  P  ! L#Z0 ( &4 ;@!V '\ AP O "  *  " ) *-  ! )D    !
  1607. 6 #H 4P/J       Z  D#ZP       '\ 
  1608.  
  1609. end
  1610. SHAR_EOF
  1611. cat << \SHAR_EOF > regmagic.h
  1612. /*
  1613.  * The first byte of the regexp internal "program" is actually this magic
  1614.  * number; the start node begins in the second byte.
  1615.  */
  1616. #define    MAGIC    0234
  1617. SHAR_EOF
  1618. cat << \SHAR_EOF > regsub.c
  1619. /*
  1620.  * regsub @(#)regsub.c    1.3 of 2 April 86 
  1621.  *
  1622.  * Copyright (c) 1986 by University of Toronto. Written by Henry Spencer.  Not
  1623.  * derived from licensed software. 
  1624.  *
  1625.  * Permission is granted to anyone to use this software for any purpose on any
  1626.  * computer system, and to redistribute it freely, subject to the following
  1627.  * restrictions: 
  1628.  *
  1629.  * 1. The author is not responsible for the consequences of use of this
  1630.  * software, no matter how awful, even if they arise from defects in it. 
  1631.  *
  1632.  * 2. The origin of this software must not be misrepresented, either by explicit
  1633.  * claim or by omission. 
  1634.  *
  1635.  * 3. Altered versions must be plainly marked as such, and must not be
  1636.  * misrepresented as being the original software. 
  1637.  */
  1638. #include <stdio.h>
  1639. #ifdef AMIGA
  1640. #include "regexp.h"
  1641. #else
  1642. #include <regexp.h>
  1643. #endif
  1644. #include "regmagic.h"
  1645.  
  1646. #ifndef CHARBITS
  1647. #define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  1648. #else
  1649. #define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  1650. #endif
  1651.  
  1652. /*
  1653.  * - regsub - perform substitutions after a regexp match 
  1654.  */
  1655. void
  1656. regsub(prog, source, dest)
  1657.     regexp         *prog;
  1658.     char           *source;
  1659.     char           *dest;
  1660. {
  1661.     register char  *src;
  1662.     register char  *dst;
  1663.     register char   c;
  1664.     register int    no;
  1665.     register int    len;
  1666.     extern char    *strncpy();
  1667.  
  1668.     if (prog == NULL || source == NULL || dest == NULL) {
  1669.     regerror("NULL parm to regsub");
  1670.     return;
  1671.     }
  1672.     if (UCHARAT(prog->program) != MAGIC) {
  1673.     regerror("damaged regexp fed to regsub");
  1674.     return;
  1675.     }
  1676.     src = source;
  1677.     dst = dest;
  1678.     while ((c = *src++) != '\0') {
  1679.     if (c == '&')
  1680.         no = 0;
  1681.     else if (c == '\\' && '0' <= *src && *src <= '9')
  1682.         no = *src++ - '0';
  1683.     else
  1684.         no = -1;
  1685.  
  1686.     if (no < 0) {        /* Ordinary character. */
  1687.         if (c == '\\' && (*src == '\\' || *src == '&'))
  1688.         c = *src++;
  1689.         *dst++ = c;
  1690.     } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
  1691.         len = prog->endp[no] - prog->startp[no];
  1692.         (void) strncpy(dst, prog->startp[no], len);
  1693.         dst += len;
  1694.         if (len != 0 && *(dst - 1) == '\0') {    /* strncpy hit NUL. */
  1695.         regerror("damaged match string");
  1696.         return;
  1697.         }
  1698.     }
  1699.     }
  1700.     *dst++ = '\0';
  1701. }
  1702. SHAR_EOF
  1703. #    End of shell archive
  1704. exit 0
  1705. -- 
  1706. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1707. Have five nice days.
  1708.